----------------------------------------------------------------------------------
-- Company: GVSU
-- Engineer: Paul Shields
-- 
-- Create Date:    15:06:21 02/25/2010 
-- Design Name: 
-- Module Name:    characters - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
-- This module gets coordinates from the CPU and H and V position from
-- the vga driver and uses them to draw the characters on the screen.
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.numeric_std.all;

---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity characters is
    Port ( clk : in STD_LOGIC; 
			  xpos : in STD_LOGIC_VECTOR (10 downto 0); --ball x coordinate
			  ypos : in STD_LOGIC_VECTOR (10 downto 0); --ball y coordinate
			  theta : in STD_LOGIC_VECTOR (4 downto 0); --theta value (0-90)
			  epsilon : in STD_LOGIC_VECTOR (3 downto 0); --epsilon value (0-.96875)
			  blank : in STD_LOGIC;
			  hcount : in  STD_LOGIC_VECTOR (10 downto 0);
           vcount : in  STD_LOGIC_VECTOR (10 downto 0);
           RED : out  STD_LOGIC_VECTOR(2 downto 0); -- Red channel output
			  BLU : out  STD_LOGIC_VECTOR(1 downto 0); -- Blue channel output
			  GRN : out  STD_LOGIC_VECTOR(2 downto 0)); -- Green channel output
end characters;

architecture Behavioral of characters is

	constant TV : INTEGER := 20;
	constant TH : integer := 540;
	constant EV : integer := 50;
	constant EH : integer := 540;
	SIGNAL the : Integer  range 0 to 524;
	SIGNAL eps : Integer  range 0 to 100;
	SIGNAL ROM_ADDRESS : STD_LOGIC_VECTOR(9 downto 0);
	SIGNAL ROM_DATA : STD_LOGIC_VECTOR(87 downto 0);
	SIGNAL ROM2_ADDRESS : STD_LOGIC_VECTOR(3 downto 0);
	SIGNAL ROM2_DATA : STD_LOGIC_VECTOR(11 downto 0);

	-- this is the character rom stuff
	component chars
		port (
		clka: IN std_logic;
		addra: IN std_logic_VECTOR(9 downto 0);
		douta: OUT std_logic_VECTOR(87 downto 0));
	end component;
	
	component ball
		port (
		clka: IN std_logic;
		addra: IN std_logic_VECTOR(3 downto 0);
		douta: OUT std_logic_VECTOR(11 downto 0));
	end component;
-- Synplicity black box declaration
attribute syn_black_box : boolean;
attribute syn_black_box of chars: component is true;
attribute syn_black_box of ball: component is true;


begin
	-- this is the character rom... 
	ROM1 : chars
			port map (
				clka => clk,
				addra => ROM_ADDRESS,
				douta => ROM_DATA);
	ROM2 : ball
		port map (
			clka => clk,
			addra => ROM2_ADDRESS,
			douta => ROM2_DATA);
			
	process (clk)
	begin	
	case theta is
		when "00000" =>  --0
		the<=18;
		when "00001" => --5
		the<=46;
		when "00010" => --10
		the<=74;
		when "00011" => --16
		the<=102;
		when "00100" => --21
		the<=130;
		when "00101" => --26
		the<=158;
		when "00110" => --32
		the<=186;
		when "00111" => --37
		the<=214;
		when "01000" => --45
		the<=242;
		when "01001" => --48
		the<=270;
		when "01010" => --50
		the<=298;
		when "01011" => --55
		the<=326;
		when "01100" => --60
		the<=354;
		when "01101" => --65
		the<=382;
		when "01110" => --70
		the<=410;
		when "01111" => --75
		the<=438;
		when "10000" => --90
		the<=466;
		when "10001" => -- special
		the<=494;
		when others =>
		the<=270;
	end case;
	
	case epsilon is
		when "0000" => 
		eps<=0;
		when "0001" => 
		eps<=5;
		when "0010" => 
		eps<=10;
		when "0011" => 
		eps<=15;
		when "0100" => 
		eps<=20;
		when "0101" => 
		eps<=25;
		when "0110" => 
		eps<=30;
		when "0111" => 
		eps<=35;
		when "1000" => 
		eps<=40;
		when "1001" => 
		eps<=45;
		when "1010" => 
		eps<=50;
		when "1011" => 
		eps<=55;
		when "1100" => 
		eps<=60;
		when "1101" => 
		eps<=65;
		when "1110" => 
		eps<=70;
		when "1111" => 
		eps<=80;
		when others =>
		end case;
	end process;
	
	
	PROCESS (clk)
	-- these variables are the row and collumn on the screen and some delay variables to help with position
	VARIABLE row, col : Natural RANGE 0 to 640;
	VARIABLE col1,col2,col3 : natural RANGE 0 to 640;
	-- these are the x and y draw start position of the characters starting at the top left corner
	VARIABLE xstart, ystart : INTEGER RANGE 0 to 640; 
	-- this is a temp for cycling through the rom line by line
	VARIABLE trackRow : INTEGER;
	BEGIN
		if( rising_edge(clk)) then
			-- set outputs to prevent latches
			RED<="000";
			
			-- get all the inputs into variables...
			row := CONV_INTEGER(vcount);
			-- except this, this is a delay thing
			col3 := col2;
			col2 := col1;
			col1 := col;
			col := CONV_INTEGER(hcount);
			xstart := CONV_INTEGER(xpos);
			ystart := CONV_INTEGER(ypos);
	
			IF col3>=xstart AND col3<=(xstart+11) AND row>=(480-ystart-12) AND row<=(480-ystart+11-12) THEN
			-- set the number of rows left to read from the rom
			trackRow := row - (480-ystart-12);
			-- read the rom and display output
			ROM2_ADDRESS <= std_logic_vector(to_unsigned(trackRow,ROM2_ADDRESS'LENGTH));
				IF ROM2_DATA(col3 -xstart) = '1' THEN
					RED<="111";
				ELSE
					RED<="000";
				END IF;
			END IF;
	end if;
	END PROCESS;


-- This is the onscreen display driver for the variables theta and epsillon
	PROCESS (clk)
	-- these variables are the row and collumn on the screen and some delay variables to help with position
	VARIABLE row, col : Natural RANGE 0 to 640;
	VARIABLE col1,col2,col3 : natural RANGE 0 to 640;
	-- this is a temp for cycling through the rom line by line
	VARIABLE trackRow : INTEGER;
	BEGIN
		if( rising_edge(clk)) then
			-- set outputs to prevent latches
			GRN<="000";
			trackrow := 0;
			
			-- get all the inputs into variables...
			row := CONV_INTEGER(vcount);
			-- except this, this is a delay thing
			col3 := col2;
			col2 := col1;
			col1 := col;
			col := CONV_INTEGER(hcount);
	
			IF col3>=TH AND col3<=(TH+87) AND row>=TV AND row<=(TV+25) THEN
				-- set the number of rows left to read from the rom
				trackRow := (the+row-TV);
				-- read the rom and display output
				ROM_ADDRESS <= std_logic_vector(to_unsigned(trackRow,ROM_ADDRESS'LENGTH));
				IF ROM_DATA(col3 -TH) = '1' THEN
					GRN<="111";
				ELSE
					GRN<="000";
				END IF;
			elsIF col3>=EH AND col3<=(EH+87) AND row>=EV AND row<=(EV+12) THEN
				-- set the number of rows left to read from the rom
				trackRow := (2+row-EV);
				-- read the rom and display output
				ROM_ADDRESS <= std_logic_vector(to_unsigned(trackRow,ROM_ADDRESS'LENGTH));
				IF ROM_DATA(col3 -EH) = '1' THEN
					GRN<="111";
				ELSE
					GRN<="000";
				END IF;
			END IF;
			
	end if;
	END PROCESS;


-- This drives the power bar!
	PROCESS (clk)
	-- these variables are the row and collumn on the screen and some delay variables to help with position
	VARIABLE row, col : Natural RANGE 0 to 640;
	VARIABLE col1,col2,col3 : natural RANGE 0 to 640;
	-- this is a temp for cycling through the rom line by line
	BEGIN
		if( rising_edge(clk)) then
			-- set outputs to prevent latches
			BLU<="00";
			
			-- get all the inputs into variables...
			row := CONV_INTEGER(vcount);
			-- except this, this is a delay thing
			col3 := col2;
			col2 := col1;
			col1 := col;
			col := CONV_INTEGER(hcount);
	
			
			IF col3>=EH+15 AND col3<=(EH+eps) AND row>=EV AND row<=(EV+12) THEN
					BLU<="11";
			ELSE
					BLU<="00";
			END IF;
			
	end if;
	END PROCESS;

end Behavioral;